package com.zebra.register;

import com.zebra.common.OnlineType;
import com.zebra.common.ZebraException;
import com.zebra.common.concurrent.ZebraExecutorManager;
import com.zebra.remoting.CommandHandler;
import com.zebra.remoting.NotifyProxy;
import com.zebra.remoting.config.*;
import com.zebra.remoting.connection.Connection;
import com.zebra.remoting.protocol.ZebraCommand;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * TMS 服务器 需要继承这个 handler
 * sk
 */
@Service
@Slf4j
public abstract class RegisterClientHandler implements CommandHandler {

    @Autowired
    private RegisterServerService registerServerService;
    @Autowired
    private ServerRedisService serverRedisService;
    @Autowired
    private RelationService relationService;

    @Override
    public void handleCommand(ChannelHandlerContext ctx, Object msg) throws Exception {
        ZebraCommand zebraCommand = (ZebraCommand) msg;
        zebraCommand.setChannel(ctx.channel());
        if (BasisCommandCode.PING.cmd() == zebraCommand.getCmd()) {
            return;
        }

        if (BasisCommandCode.REGISTER.cmd() == zebraCommand.getCmd()) {
            NotifyProxy.notifyProxy.ackSyncMsg(ctx.channel(), zebraCommand);
            return;
        }

        ZebraExecutorManager.getInstance().getDefaultExecutor().execute(() ->  doHandlerRead(zebraCommand));
    }

    private void doHandlerRead(ZebraCommand zebraCommand){
        try {
            BasisCommandCode commandCode = (BasisCommandCode) BasisCommandCode.valueOfCode(zebraCommand.getCmd());
            switch (commandCode){

                case LINKSTORA: {
                    LINKSTORAmessage links = (LINKSTORAmessage) zebraCommand.getRequest();
                    if (null == links || links.getServerId() < 1){
                        log.error("LINKSTORA links info is null  {}", null == links ? "" : links.toString());
                        return;
                    }
                    log.info("LINKSTORA links info  {}", links.toString());
                    registerServerService.updateLinks(links);
                    return;
                }

                case ONNUMTORA: {
                    ONNUMTORAmessage links = (ONNUMTORAmessage) zebraCommand.getRequest();
                    if (null == links || links.getServerId() < 1){
                        log.error("ONNUMTORA online number  is null  {}", null == links ? "" : links.toString());
                        return;
                    }
                    log.info("ONNUMTORA online number {}", links.toString());
                    registerServerService.updateOnlineNumber(links);
                    return;
                }

                case TMSTORA: {
                    List<Connection> tmsConnetions = RegisterConfigInfoManager.getInstance().getTmsServers();
                    sendTMSTORA(tmsConnetions, null);
                    Connection connection = Connection.getByChannel(zebraCommand.getChannel());
                    List<Connection> gwConnetions = RegisterConfigInfoManager.getInstance().getGateways();
                    sendTMSTORA(gwConnetions, connection);
                    return;
                }

            }
            //---------其他消息-------------
            doHandler(zebraCommand);
        }catch (ZebraException e){
            log.error("Handler process zebraException {} {} {}", e.getMessage(), zebraCommand.toString());
            zebraCommand.sendFailureCode(e.getExceptionCode());
        }catch (Exception e) {
            log.error(String.format("Handler process exception CMD: %d %s %s ", zebraCommand.getCmd(), zebraCommand.toString(), e));
            zebraCommand.sendFailureCode( StateCode.SysException.code());
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Connection connection = Connection.getByChannel(ctx.channel());
        if (null == connection){
            return;
        }

        /** 应该由 leader 执行生杀权
         * 关闭TMS自动关闭该TMS 玩家自动下线状态，以防卡房间； 【大厅，slots 自动切换，如果是棋牌或者其他无操作，则1分钟自动清理下线】 */
        log.info("Register Handler Inactive connection {}", connection.toString());
        if (ServerType.Gateway.value() == connection.getSeverType().value()){
            RegisterConfigInfoManager.getInstance().removeGateway(connection.getServerId());
            if (RegisterConfigInfoManager.getInstance().getRelationManager().checkIsLeader()){
                serverRedisService.removeGw(connection.getServerId());
            }else {
                relationService.removeGateway(connection.getServerId());
            }
        }else {
            RegisterConfigInfoManager.getInstance().removeTms(connection.getServerId());
            if (RegisterConfigInfoManager.getInstance().getRelationManager().checkIsLeader()){
                TmsServerInfo serverInfo = serverRedisService.removeTms(connection.getServerId());
                if (null != serverInfo){
                    int serverType = serverInfo.getVfxs().contains("LOBBY,") ? 0 : 1;
                    ZebraExecutorManager.getInstance().getDefaultScheduler().schedule(()->tmsOffline(connection.getServerId(), serverType), 60,  TimeUnit.SECONDS, ZebraExecutorManager.getInstance().getDefaultExecutor());
                }
            }else {
               relationService.removeTms(connection.getServerId());
            }

        }
        registerServerService.printRegisterLog();
    }

    private void sendTMSTORA(List<Connection> tmsConnections, Connection connection){
        if (null == tmsConnections || tmsConnections.isEmpty()){
            return;
        }
        for (Connection c : tmsConnections){
            if (null != c  && !c.equals(connection)){
                ZebraCommand remotingCommand = new ZebraCommand();
                remotingCommand.setCmd(BasisCommandCode.TMSTORA.cmd());
                remotingCommand.setResponse(new EmptyMessage());
                c.writeAndFlush(remotingCommand);
            }
        }
    }

    //serverType : lobby =0; tms = 1
    private void tmsOffline(int tmsid, int serverType){
        TmsServerInfo serverInfo = serverRedisService.getTmsById(tmsid);
        if (null == serverInfo){
            doTmsOffline(tmsid, serverType);
        }
    }

    public abstract  void doHandler(ZebraCommand command)throws Exception;

    public abstract void doTmsOffline(int tmsServerId, int serverrType);


}
